package `in`.srain.cube.util.log

import `in`.srain.cube.app.lifecycle.AppActivityLifecycleCallbacks
import `in`.srain.cube.util.NetworkStatusManager
import `in`.srain.cube.util.time.TimeData
import android.text.TextUtils
import android.util.ArrayMap
import java.text.SimpleDateFormat
import java.util.*

class LogEvent(eventName: String) {

    companion object {
        private const val CHAR_EMPTY = " "
        private const val KEY_EVENT_NAME = "eventName"
        private const val KEY_CTIME = "ctime"
        private const val KEY_NETWORK = "network"
        private const val KEY_IS_FOREGROUND = "isForeground"
        private const val KEY_USED_DURATION = "usedDuration"

        private val DATE_FORMAT: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault())

        private val BASE_JSON: MutableMap<String, Any?> = ArrayMap()

        private fun checkKey(key: String) {
            if (TextUtils.isEmpty(key) || key.contains(CHAR_EMPTY)) {
                throw RuntimeException("Illegal key for LogEvents")
            }
        }

        private fun setData(map: MutableMap<String, Any?>, key: String, value: Any?) {
            map[key] = value
        }

        @JvmStatic
        fun putBaseData(key: String, value: Any?) {
            checkKey(key)
            synchronized(BASE_JSON) {
                BASE_JSON.put(key, value)
            }
        }
    }

    // api-request:   api: send-comment, active, tc: 200ms, data-size:
    // download-image host, tc, size, width, height
    // chat-service:  fail, successful
    private val map: MutableMap<String, Any?> = mutableMapOf<String, Any?>().apply {
        synchronized(BASE_JSON) {
            this[KEY_EVENT_NAME] = eventName
            this[KEY_CTIME] = DATE_FORMAT.format(TimeData.getInstance().serverTime)
            this[KEY_NETWORK] = NetworkStatusManager.getInstance().networkTypeName
            this[KEY_IS_FOREGROUND] = AppActivityLifecycleCallbacks.getInstance().isAppInForeground
            this[KEY_USED_DURATION] = TimeData.getInstance().usedDuration
            this.putAll(BASE_JSON)
        }
    }

    fun putData(key: String, value: Any?): LogEvent {
        checkKey(key)
        return setData(key, value)
    }

    private fun setData(key: String, value: Any?): LogEvent {
        setData(map, key, value)
        return this
    }

    val eventData: Map<String, Any?>
        get() = map

    fun startTimeForKey(key: String): LogEvent {
        setData(key, System.currentTimeMillis())
        return this
    }

    fun endTimeForKey(key: String): LogEvent {
        val time = System.currentTimeMillis() - map.getOrElse(key) { System.currentTimeMillis() } as Long
        map.remove(key)
        putData(key, time)
        return this
    }

    override fun toString(): String {
        return map.toString()
    }
}